﻿namespace LiteBlog.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using LiteBlog.Common;

    using LiteBlog.Models;
    using LiteBlog.Controllers.Helpers;
    using LiteBlog.Components;
    using System.Web.Script.Serialization;
    using System.IO;
    using System.Text;
    using LiteBlog.Controllers.Filters;
    using LiteBlog.Common.Entities;
    using LiteBlog.Common.Components;
    using LiteBlog.Components.Contracts;
    using LiteBlog.Controllers.Contracts;

    public class PostController : CompController<PostInfo, string>, IPostController
    {
        private IBlogComp _blogComp = null;
        private ICategoryComp _categoryComp;
        private IPostComp _postComp;
        private IStatComp _statComp;
        private IDocumentComp _documentComp;
        private IAuthorComp _authorComp;
        private ITagComp _tagComp;
        

        public ICategoryComp CategoryComponent
        {
            get
            {
                return _categoryComp;
            }
        }

        public IPostComp PostComponent
        {
            get
            {
                return _postComp;
            }
        }

        public IStatComp StatComponent
        {
            get
            {
                return _statComp;
            }
        }

        public IDocumentComp DocumentComponent
        {
            get
            {
                return _documentComp;
            }
        }
        public IAuthorComp AuthorComponent
        {
            get
            {
                return _authorComp;
            }
        }

        public ITagComp TagComponent
        {
            get
            {
                return _tagComp;
            }
        }

        public IBlogComp BlogComponent { get { return _blogComp; } }

        public PostController(IBlogComp blogComp, 
            IPostComp postComp, 
            ICategoryComp categoryComp, 
            ITagComp tagComp, 
            IStatComp statComp, 
            IDocumentComp documentComp, 
            IAuthorComp authorComp, 
            ISettingsComp settingsComp, 
            ICacheComp cacheComp)
            : base(blogComp, settingsComp, cacheComp)
        {
            _blogComp = blogComp;
            _postComp = postComp;
            _categoryComp = categoryComp;
            _tagComp = tagComp;
            _statComp = statComp;
            _documentComp = documentComp;
            _authorComp = authorComp;
        }

        public override ActionResult Manage()
        {
            var collection = _component.Get();
            if (collection != null && collection.Count() > 0)
                foreach (var post in collection)
                    post.FormattedTime = post.Time.ToString(DisplayHelper.ShortDateFormat, null);

            return View("Manage", GetAdminLayout(), collection);
        }

        public override ActionResult Create(PostInfo model)
        {
            throw new NotImplementedException();
        }

        public override ActionResult Update(string olid, PostInfo model)
        {
            throw new NotImplementedException();
        }

        public override ActionResult Delete(string id)
        {
            BlogComponent.DeleteAttachments(id);
            return base.Delete(id);
        }

        [HttpGet]
        [Authorize]
       public ActionResult Compose(string id)
        {
            DraftPost post = null;
            if (string.IsNullOrEmpty(id))
            {
                // called from compose
                post = new DraftPost();
                post.Time = DateTimeHelper.Now;
                post.Type = DraftType.New;
            }
            else
            {
                // called from edit
                if (DraftPost.IsDraft(id))
                    post = (DraftPost)PostComponent.Load(id);
                else
                    post = PostComponent.EditPublished(id);
            }

            post.FormattedTime = post.Time.ToString(DisplayHelper.CalendarDateFormat, null);
            post.Author = User.Identity.Name;
            var categories = CategoryComponent.Get().Select(c => new { Id = c.CatID, Name = c.Name });
            var tags = TagComponent.Get().Select(t => new { Id = t.TagId, Name = t.Name });
            var serializer = new JavaScriptSerializer();
            var model = new
            {
                Post = post,
                Categories = categories,
                Tags = tags
            };
            ViewBag.Json = serializer.Serialize(model);
            return View("Compose", GetAdminLayout(), null);
        }

        [PostNotFoundFilter(Order = 1)]
        [CrawlerFilterForPost(Order = 2)]
        [PageExceptionFilter]
        public ActionResult Index(string id)
        {
            // Redirect with the right URL if required.
            // id2 is got from the NotFoundFilter
            string id2 = RouteData.Values["id2"].ToString();
            if (id != id2)
                return RedirectToAction("Index", new { id = id2 });

            var postModel = new PostModel();
            var post = PostComponent.Load(id);
            ViewBag.Title = post.Title;
            DisplayHelper.SetDisplayTime(post);
            postModel.Post = post;

            if (User.Identity.IsAuthenticated)
                postModel.Author = AuthorComponent.Get(User.Identity.Name);

            RouteData.Values["post"] = post;
            StatComponent.IncrementPosts(id);
            return View("Index", GetSiteLayout(), postModel);
        }

        [HttpPost]
        [ValidateInput(false)]
        [ValidateFilter]
        [Authorize]
        public ActionResult Publish(DraftPost post)
        {
            UpdatePost(post);
            PostComponent.Save(post);
            var result = _blogComp.Publish(post);
            var resultModel = GetResultModel(result, post.Title);
            var resultModelWithData = new ResultModelWithData<string>(resultModel, post.FileID);
            return Json(resultModelWithData);
        }

        [HttpGet]
        [Authorize]
        public ActionResult Unpublish(string id, string title)
        {
            string draftId;
            var result = _blogComp.Unpublish(id, out draftId);
            var resultModel = GetResultModel(result, title);
            var resultModelWithData = new ResultModelWithData<string>(resultModel, draftId);
            return Json(resultModelWithData, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        [ValidateInput(false)]
        [ValidateFilter]
        [Authorize]
        [AjaxExceptionFilter]
        public ActionResult Save(DraftPost post)
        {
            UpdatePost(post);
            var result = PostComponent.Save(post);
            var resultModel = GetResultModel(result, DateTimeHelper.Now.ToString("hh:mm:ss tt"));
            var resultModelWithData = new ResultModelWithData<string>(resultModel, post.Type == DraftType.New ? post.DraftID : string.Empty);
            return Json(resultModelWithData);
        }

        [HttpPost]
        [Authorize]
        [AjaxExceptionFilter]
        public ActionResult Upload(string fileId)
        {
            var absUrls = new List<string>();
            var relUrls = new List<string>();
            if (Request.Files != null && Request.Files.Count > 0)
            {
                for (int idx = 0; idx < Request.Files.Count; idx++)
                {
                    var file = Request.Files[idx];
                    if (file.ContentLength > 0)
                    {
                        var document = DocumentComponent.GetNew(file.FileName);
                        file.SaveAs(document.PhysicalPath);
                        absUrls.Add(document.VirtualPath);
                    }
                }
            }
            return Json(absUrls);
        }

        [HttpGet]
        [AjaxExceptionFilter]
        [Authorize]
        public ActionResult DeleteAttachment(string id, string fileId)
        {
            bool remove = true;
            // if you attach without saving the file, and then delete attachment, fileId will be empty.
            if (!string.IsNullOrEmpty(fileId))
                remove = PostComponent.DeleteAttachment(fileId, id);
            if (remove)
                DocumentComponent.Remove(id);

            return Json(new ResultModel { Result = true }, JsonRequestBehavior.AllowGet);
        }


        private void UpdatePost(DraftPost post)
        {
            if (string.IsNullOrEmpty(post.DraftID))
            {
                var postInfo = post.AsPostInfo();
                _blogComp.Create(postInfo);
                post.DraftID = postInfo.FileID;
            }
            else
            {
                // Merge the comments from the draft
                // This is a good place to create the draft document
                // instead of EditPublished.
                var savedPost = PostComponent.Load(post.DraftID);
                post.Comments = savedPost.Comments.ToList();
            }
            post.Author = User.Identity.Name;
            post.UpdatedTime = DateTimeHelper.Now;
        }

        protected override string[] GetMessageParams(PostInfo model)
        {
            return new string[] { model.Title };
        }

        public override void ResolveComponents()
        {

        }
    }
}